package com.norns.torque.view

import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.CornerPathEffect
import android.graphics.DashPathEffect
import android.graphics.Paint
import android.graphics.Path
import android.graphics.PathEffect
import android.graphics.Point
import android.graphics.PointF
import android.graphics.Rect
import android.graphics.RectF
import android.util.ArrayMap
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.VelocityTracker
import android.view.View
import android.widget.Scroller
import androidx.core.content.ContextCompat
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LifecycleRegistry
import androidx.lifecycle.lifecycleScope
import com.norns.torque.R
import com.norns.torque.entrty.DeviceConfig
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import timber.log.Timber


class ChartView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0,
) : View(context, attrs, defStyleAttr), LifecycleOwner {
    private var heightStep: Float = 0f
    private var widthStep: Float = 0f
    private val leftStart: Float
    private val bottomStart: Float
    private val endMarge: Float
    private val pathEffect: PathEffect
    private val cornerPathEffect: PathEffect
    private var linePaint = Paint(Paint.ANTI_ALIAS_FLAG)
    private var pathPaint = Paint(Paint.ANTI_ALIAS_FLAG)
    private var textPaint = Paint(Paint.ANTI_ALIAS_FLAG)
    private val path: Path = Path()
    private var pathMeasure: Path = Path()
    private val mScroller: Scroller
    private var scrollEndX: Float = 0f
    private var contentWidth: Float = 0f
    private var drawStartY: Float = 0f
    private var isTouch: Boolean = true

    // 速度追踪
    private val mVelocityTracker: VelocityTracker = VelocityTracker.obtain()

    // 水平平移记录点
    private var lastX = 0f
    private val lifecycleRegistry: LifecycleRegistry = LifecycleRegistry(this)
    private var arrayMap: ArrayMap<String, Pair<PointF, PointF>> =
        ArrayMap<String, Pair<PointF, PointF>>()
    private var showMaxText: Boolean = false

    init {
        mScroller = Scroller(context)
        linePaint.color = Color.BLACK
        linePaint.strokeWidth = 2f
        linePaint.style = Paint.Style.FILL

        pathPaint.color = ContextCompat.getColor(context, R.color.chatColor)
        pathPaint.strokeWidth = 2f
        pathPaint.style = Paint.Style.FILL

        textPaint.color = ContextCompat.getColor(context, R.color.blackText)
        textPaint.strokeWidth = 2f
        //线头形状
        linePaint.setStrokeCap(Paint.Cap.ROUND)
        //连接形状
        linePaint.setStrokeJoin(Paint.Join.MITER)

        val textSize = context.resources.getDimension(R.dimen.text14)
        linePaint.textSize = textSize
        textPaint.textSize = textSize

        leftStart = context.resources.getDimension(R.dimen.w45)
        bottomStart = context.resources.getDimension(R.dimen.w10)
        endMarge = context.resources.getDimension(R.dimen.w10)
        widthStep = context.resources.getDimension(R.dimen.w8)
        pathEffect = DashPathEffect(floatArrayOf(10f, 5f), 10f)
        cornerPathEffect = CornerPathEffect(5f)
        pathPaint.setPathEffect(cornerPathEffect)
        //paint.setPathEffect(pathEffect)
        path.reset()
        addOnAttachStateChangeListener(object : View.OnAttachStateChangeListener {
            // View onDetached 的时候调用 onDestroy()
            override fun onViewDetachedFromWindow(v: View) {
                // 在Lifecycle被销毁之后，协程会跟着取消
                onDestroy()
            }

            // View onAttached 的时候调用 onStart()
            override fun onViewAttachedToWindow(v: View) {
                onStart()
            }
        })

    }

    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        heightStep = (h - bottomStart * 2) / 21f
        contentWidth = w - leftStart / 2
        drawStartY = h - bottomStart
        Timber.d("onSizeChanged 宽度:${w}  ------  高度:${h}")
    }

    override fun onTouchEvent(event: MotionEvent): Boolean {
        if (scrollEndX <= 0) return super.onTouchEvent(event)//没有超出绘制范围
        if (!isTouch) return super.onTouchEvent(event)
        singlePoint(event)
        return true
    }

    private fun singlePoint(event: MotionEvent) {
        mVelocityTracker.addMovement(event)
        when (event.action) {
            MotionEvent.ACTION_DOWN -> lastX = event.x
            MotionEvent.ACTION_MOVE -> {
                val deltaX = event.x - lastX
                delWithActionMove(deltaX.toInt())
                lastX = event.x
            }

            MotionEvent.ACTION_UP ->                 // 计算滑动速度
                computeVelocity()
        }
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        val scrollX = getScrollX().toFloat()
        //Timber.d("onDraw 宽度:${width}  ------  高度:${height} ScrollX=${scrollX} ")
        linePaint.setColor(Color.BLACK)
        linePaint.style = Paint.Style.FILL
        linePaint.setPathEffect(null)
        //绘制Y轴
        canvas.drawLine(
            leftStart + scrollX,
            height - bottomStart,
            width + scrollX,
            height - bottomStart,
            linePaint
        )
        //绘制Y轴
        canvas.drawLine(
            leftStart + scrollX,
            height - bottomStart,
            leftStart + scrollX,
            bottomStart,
            linePaint
        )
        canvas.drawPath(pathMeasure, pathPaint)
        if (showMaxText) {
            arrayMap.forEach { (t, v) ->
                val firstPoint = v.first
                val secondPoint = v.second
                val w = textPaint.measureText(t)
                canvas.drawLine(
                    firstPoint.x,
                    firstPoint.y,
                    firstPoint.x + w,
                    firstPoint.y,
                    textPaint
                )
                canvas.drawText(t, firstPoint.x, firstPoint.y - 2, textPaint)
                if (firstPoint.y != secondPoint.y) {
                    canvas.drawLine(
                        firstPoint.x + w,
                        firstPoint.y,
                        secondPoint.x,
                        secondPoint.y,
                        textPaint
                    )
                }
            }
        }

        linePaint.setColor(Color.WHITE)
        linePaint.style = Paint.Style.FILL
        canvas.drawRect(scrollX, 0f, leftStart + scrollX, height.toFloat(), linePaint)
        val unitValue = Math.round(DeviceConfig.range / 21f)
        //绘制左边文字
        for (i in 0..21) {
            linePaint.setColor(Color.BLACK)
            val value = (i * unitValue)
            val text = if (value > DeviceConfig.range) {
                DeviceConfig.range.toString()
            } else {
                value.toString()
            }
            val textWidth = linePaint.measureText(text)
            val textLeft = leftStart - textWidth - (endMarge / 2) + scrollX
            val lineBottom = height - bottomStart - (i * heightStep)
            val textBottom = if (i == 0) {
                height.toFloat() - linePaint.textSize / 2f
            } else {
                lineBottom + (linePaint.textSize / 2)
            }
            canvas.drawText(text, textLeft, textBottom, linePaint)
//            if (i != 0) {
//                val lineColor=context.getColor(R.color.line_color)
//                linePaint.setColor(lineColor)
//                linePaint.setPathEffect(pathEffect)
//                canvas.drawLine(leftStart+scrollX, lineBottom, width - endMarge+scrollX, lineBottom, linePaint)
//            }
        }

    }


    private var lastValue: Float = 0.0f
    private var lastEqualCount: Int = 0
    private var lastPathX = 0f
    fun setTrackValue(value: Float) {
        lifecycleScope.launch {
            withContext(Dispatchers.Default) {
                val newValue = if (value < 0) {
                    0f
                } else {
                    value
                }
                if (newValue == lastValue) {
                    lastEqualCount += 1
                    if (newValue != 0f) {
                        createPath(newValue)
                    } else {
                        if (lastEqualCount < 5) {
                            createPath(newValue)
                        } else {
                            val width = contentWidth + scrollX
                            if (lastPathX > width) {
                                scrollEndX = scrollX + widthStep
                                val v = lastPathX - width + widthStep
                                scrollBy(v.toInt(), 0)
                            }
                        }
                    }
                } else {
                    lastEqualCount = 0
                    createPath(newValue)
                    lastValue = value
                }
            }
        }
    }

    private var maxPoint: PointF = PointF()
    private var maxValue: Float = 0f
    private var lastRectF: RectF = RectF()

    fun setSowMaxText() {
        showMaxText = !showMaxText
    }

    private fun createPath(newValue: Float) {
        if (path.isEmpty) {
            path.moveTo(leftStart, drawStartY)
            lastPathX = leftStart
            maxValue = 0f
        }
        lastPathX += widthStep
        var devValue = (newValue / DeviceConfig.range)
        if (devValue > 1.0f) {
            devValue = 1.0f
        }
        val y = drawStartY - devValue * drawStartY
        path.lineTo(lastPathX, y)
        if (showMaxText) {
            if (newValue == 0f) {
                if (maxValue != 0f) {
                    val str = maxValue.toString()
                    val textWidth = textPaint.measureText(str)
                    var rectF = RectF(
                        maxPoint.x - textWidth,
                        maxPoint.y - textPaint.textSize,
                        maxPoint.x,
                        maxPoint.y
                    )
                    var firstPointF = PointF(rectF.left, rectF.bottom)
                    if (lastRectF.isEmpty) {
                        Timber.d("空RectF")
                    } else {
                        if (lastRectF.contains(
                                rectF.left,
                                rectF.top
                            ) || lastRectF.contains(rectF.left, rectF.bottom)
                        ) {
                            Timber.d("重叠了${textPaint.textSize * 2}")
                            rectF = RectF(
                                maxPoint.x - textWidth,
                                lastRectF.top - textPaint.textSize * 2 - 5,
                                maxPoint.x,
                                lastRectF.bottom - textPaint.textSize - 5
                            )
                            firstPointF = PointF(rectF.left, rectF.bottom)
                        } else {
                            Timber.d("不重叠")
                        }
                    }
                    lastRectF = rectF
                    val secondPointF = PointF(maxPoint.x, maxPoint.y)
                    val pair = Pair<PointF, PointF>(firstPointF, secondPointF)
                    arrayMap.put(str, pair)
                }
                maxValue = 0f
                maxPoint.set(0f, 0f)
            } else {
                if (maxValue < newValue) {
                    maxValue = newValue
                    maxPoint.set(lastPathX, y)
                }
            }
        }

        pathMeasure.reset()
        pathMeasure.addPath(path)
        pathMeasure.lineTo(lastPathX, drawStartY)
        pathMeasure.close()

        val width = contentWidth + scrollX
        if (lastPathX > width) {
            //mScroller?.startScroll(scrollX, 0, pathStep.toInt(), 0, 500)
            scrollEndX = scrollX + widthStep
            scrollBy(widthStep.toInt(), 0)
        }
        postInvalidate()
    }

    /**
     * @param deltaX 处理 MOVE事件
     */
    private fun delWithActionMove(deltaX: Int) {
        val leftBorder: Int = getLeftBorder() // 左边界
        val rightBorder: Int = getRightBorder() // 右边界
        val scrollX: Int = getScrollX() // X轴滑动偏移量
        //Timber.d("滑动${deltaX} leftBorder=${leftBorder} rightBorder${rightBorder} scrollX=${scrollX}")
        if (deltaX > 0) { //手指向右滑动
            if (scrollX <= leftBorder) {
                scrollTo(leftBorder, 0)
                return
            }
            if ((scrollX - deltaX) <= leftBorder) {
                scrollTo(leftBorder, 0)//手指向左滑动
            } else {
                scrollBy(-deltaX, 0)
            }
        } else if (deltaX < 0) {
            if (scrollX >= rightBorder) {
                scrollTo(rightBorder, 0)//手指向左滑动
                return
            }
            if ((scrollX + Math.abs(deltaX)) >= rightBorder) {
                scrollTo(rightBorder, 0)//手指向左滑动
            } else {
                scrollBy(-deltaX, 0)
            }
        }
    }

    /**
     * 处理惯性滑动
     */
    override fun computeScroll() {
        if (mScroller.computeScrollOffset()) {
            scrollTo(mScroller.currX, 0)
        }
    }

    /**
     * 计算滑动速度
     */
    private fun computeVelocity() {
        mVelocityTracker.computeCurrentVelocity(500)
        val velocityX = mVelocityTracker.xVelocity
        // 初始化 Scroller
        Timber.d("velocityX = $velocityX")
        fling(
            getScrollX(), 0, -velocityX.toInt(), 0,
            getLeftBorder(), getRightBorder(), 0, 0
        )
    }

    /**
     * @param startX    起始 X
     * @param startY    起始 Y
     * @param velocityX X 方向速度
     * @param velocityY Y 方向速度
     * @param minX      左边界
     * @param maxX      右边界
     * @param minY      上边界
     * @param maxY      下边界
     */
    private fun fling(
        startX: Int, startY: Int, velocityX: Int, velocityY: Int,
        minX: Int, maxX: Int, minY: Int, maxY: Int
    ) {
        mScroller.fling(startX, startY, velocityX, velocityY, minX, maxX, minY, maxY)
    }

    /**
     * @return 左边界
     */
    private fun getLeftBorder(): Int {
        return 0
    }

    /**
     * @return 右边界
     */
    private fun getRightBorder(): Int {
        return scrollEndX.toInt()
    }

    override fun onWindowVisibilityChanged(visibility: Int) {
        super.onWindowVisibilityChanged(visibility)
        if (visibility == VISIBLE) {
            lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START)
            lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME)
            Timber.d("view 显示")
        } else if (visibility == GONE || visibility == INVISIBLE) {
            lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_PAUSE)
            lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_STOP)
            Timber.d("view 隐藏")
        }
    }

    fun onStart() {
        lifecycleRegistry.currentState = Lifecycle.State.STARTED
    }

    fun onDestroy() {
        arrayMap.clear()
        path.reset()
        lifecycleRegistry.currentState = Lifecycle.State.DESTROYED
    }

    override val lifecycle: Lifecycle
        get() = lifecycleRegistry
}